package com.zbkj.crmeb.merchant.api.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.common.CommonPage;
import com.crmeb.core.exception.CrmebException;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.utils.PriceUtil;
import com.zbkj.crmeb.chant.model.ChannelMerchant;
import com.zbkj.crmeb.enums.CouponUseStatusEnum;
import com.zbkj.crmeb.enums.CouponUseTypeEnum;
import com.zbkj.crmeb.enums.CouponUserTypeEnum;
import com.zbkj.crmeb.front.response.PriceGroupResponse;
import com.zbkj.crmeb.marketing.dao.StoreCouponDao;
import com.zbkj.crmeb.marketing.dao.StoreCouponUserDao;
import com.zbkj.crmeb.marketing.dto.CouponProductRangeDTO;
import com.zbkj.crmeb.marketing.model.StoreCoupon;
import com.zbkj.crmeb.marketing.model.StoreCouponUser;
import com.zbkj.crmeb.marketing.request.FrontStoreCouponUserRequest;
import com.zbkj.crmeb.marketing.response.FrontStoreCouponUserResponse;
import com.zbkj.crmeb.marketing.response.StoreCouponUserResponse;
import com.zbkj.crmeb.marketing.service.StoreCouponService;
import com.zbkj.crmeb.merchant.api.service.FrontCouponUserService;
import com.zbkj.crmeb.store.dao.StoreProductCouponDao;
import com.zbkj.crmeb.store.model.StoreProduct;
import com.zbkj.crmeb.store.model.StoreProductCoupon;
import com.zbkj.crmeb.store.response.StoreCartResponse;
import com.zbkj.crmeb.store.service.StoreProductCouponService;
import com.zbkj.crmeb.store.service.StoreProductMerService;
import com.zbkj.crmeb.store.service.StoreProductService;
import com.zbkj.crmeb.user.model.UserAddress;
import com.zbkj.crmeb.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ProjectName: crmeb-server
 * @Package: com.zbkj.crmeb.merchant.api.service.impl
 * @ClassName: FrontCouponUserServiceImpl
 * @author: lvmd
 * @description:
 * @date: 2022/1/17 17:13
 * @version: 1.0
 */
@Service
@Slf4j
public class FrontCouponUserServiceImpl implements FrontCouponUserService {

    @Resource
    private UserService userService;
    @Resource
    private StoreCouponService storeCouponService;
    @Autowired
    private StoreProductCouponService storeProductCouponService;
    @Autowired
    PriceUtil priceUtil;
    @Resource
    private StoreProductService storeProductService;
    @Resource
    private StoreProductMerService storeProductMerService;

    @Resource
    private StoreCouponDao storeCouponDao;
    @Resource
    private StoreCouponUserDao storeCouponUserDao;
    @Resource
    private StoreProductCouponDao storeProductCouponDao;

    /**
     * 用户领取优惠券
     *
     * @param couponId 优惠券发布id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean receiveFrontCouponUser(Integer couponId) {
        Integer userId = userService.getUserId();
        List<Integer> userIds = Arrays.asList(userId);
        // 领取优惠券
        Boolean flag = storeCouponService.bindCouponByUser(userIds, couponId, CouponUserTypeEnum.GET);
        if (flag) {
            return true;
        }
        throw new CrmebException("发放数量已领取完!");
    }

    /**
     * 我的优惠券列表
     *
     * @param request
     * @return
     */
    @Override
    public CommonPage<FrontStoreCouponUserResponse> listFrontCouponUsers(FrontStoreCouponUserRequest request) {
        if (Objects.isNull(request.getQueryType())) {
            throw new CrmebException("缺少必要参数：queryType");
        }
        request.setUserId(userService.getUserId());
        Page<StoreCouponUser> page = PageHelper.startPage(request.getPage(), request.getLimit());
        LambdaQueryWrapper<StoreCouponUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreCouponUser::getUid, request.getUserId());
        Date theDate = new Date();
        if (Objects.nonNull(request.getStatus())) {
            if (3 == request.getStatus()) {
                wrapper.and(i -> i.eq(StoreCouponUser::getStatus, CouponUseStatusEnum.USED.getCode())
                        .or()
                        .lt(StoreCouponUser::getEndTime, theDate));
            } else {
                wrapper.eq(StoreCouponUser::getStatus, request.getStatus());
            }

            if (CouponUseStatusEnum.USABLE.getCode().equals(request.getStatus())) {
                wrapper.gt(StoreCouponUser::getEndTime, theDate);
                wrapper.eq(StoreCouponUser::getStatus, request.getStatus());
            }
        }
        wrapper.orderByDesc(StoreCouponUser::getId);
        List<StoreCouponUser> storeCouponUserList = storeCouponUserDao.selectList(wrapper);
        List<FrontStoreCouponUserResponse> list = new ArrayList<>();
        storeCouponUserList.forEach(i -> {
            FrontStoreCouponUserResponse response = new FrontStoreCouponUserResponse();
            BeanUtils.copyProperties(i, response);
            response.setUseStartTime(i.getStartTime());
            response.setUseEndTime(i.getEndTime());
            // 状态非实时更新
            if (CouponUseStatusEnum.USABLE.getCode().equals(i.getStatus()) && theDate.after(response.getUseEndTime())) {
                response.setStatus(CouponUseStatusEnum.DISABLES.getCode());
            }
            list.add(response);
        });
        return CommonPage.restPage(CommonPage.copyPageInfo(page, list));
    }

    /**
     * 查询优惠券详情
     *
     * @param id 优惠券记录id
     * @return
     */
    @Override
    public FrontStoreCouponUserResponse getFrontCouponUserInfo(Integer id) {
        StoreCouponUser storeCouponUser = storeCouponUserDao.selectById(id);
        Integer userId = userService.getUserId();
        if (Objects.isNull(storeCouponUser) || !storeCouponUser.getUid().equals(userId)) {
            throw new CrmebException("当前优惠券不存在");
        }
        if (!CouponUseStatusEnum.USABLE.getCode().equals(storeCouponUser.getStatus())) {
            throw new CrmebException("当前优惠券已使用或已过期");
        } else {
            if (new Date().after(storeCouponUser.getEndTime())) {
                // 更新优惠券状态
                StoreCouponUser updateCouponUser = new StoreCouponUser();
                updateCouponUser.setId(storeCouponUser.getId());
                updateCouponUser.setStatus(CouponUseStatusEnum.DISABLES.getCode());
                storeCouponUserDao.updateById(updateCouponUser);
                throw new CrmebException("当前优惠券已过期");
            }
        }
        StoreCoupon storeCoupon = storeCouponDao.selectById(storeCouponUser.getCouponId());
        if (Objects.isNull(storeCoupon)) {
            throw new CrmebException("优惠券不存在");
        }
        FrontStoreCouponUserResponse response = new FrontStoreCouponUserResponse();
        BeanUtils.copyProperties(storeCouponUser, response);

        response.setRemark(storeCoupon.getRemark());
        response.setNotice(storeCoupon.getNotice());
        response.setUseStartTime(storeCouponUser.getStartTime());
        response.setUseEndTime(storeCouponUser.getEndTime());

        return response;
    }

    /**
     * 统计可用优惠券数量
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public Integer countFrontUsableCouponUser(Integer userId) {
        return storeCouponUserDao.selectCount(new LambdaQueryWrapper<StoreCouponUser>()
                .eq(StoreCouponUser::getUid, userId)
                .eq(StoreCouponUser::getStatus, CouponUseStatusEnum.USABLE.getCode())
                .gt(StoreCouponUser::getEndTime, new Date())
        );
    }

    /**
     * 查询优惠券品类券对象
     *
     * @param couponId 用户优惠券id
     * @return
     */
    @Override
    public CouponProductRangeDTO getCouponProductRangeDTO(Integer couponId) {
        StoreCouponUser storeCouponUser = storeCouponUserDao.selectById(couponId);
        Integer userId = userService.getUserId();
        if (Objects.isNull(storeCouponUser) || !storeCouponUser.getUid().equals(userId)) {
            throw new CrmebException("当前优惠券不存在");
        }
        if (CouponUseTypeEnum.CATE.getCode().equals(storeCouponUser.getUseType()) && StringUtils.isNotBlank(storeCouponUser.getPrimaryKey())) {
            return JSONObject.parseObject(storeCouponUser.getPrimaryKey(), CouponProductRangeDTO.class);
        }
        return null;
    }


    @Override
    public StoreCouponUser getById(Integer id) {
        return storeCouponUserDao.selectById(id);
    }

    /**
     * 获取指定商品id
     *
     * @param couponId 优惠券发布id
     * @return
     */
    @Override
    public List<Integer> listCouponUserProductId(Integer couponId) {
        List<StoreProductCoupon> list = storeProductCouponDao.selectList(new LambdaQueryWrapper<StoreProductCoupon>()
                .select(StoreProductCoupon::getProductId)
                .eq(StoreProductCoupon::getIssueCouponId, couponId)
        );
        if (CollectionUtils.isEmpty(list)) {
            return Collections.singletonList(0);
        }
        return list.stream().map(StoreProductCoupon::getProductId).collect(Collectors.toList());
    }

    /**
     * 查询购物车商品可用优惠券
     *
     * @param storeCartResponse
     * @return
     */
    @Override
    public List<StoreCouponUserResponse> getCanUseUserCouponList(List<StoreCartResponse> storeCartResponse, FrontStoreCouponUserRequest request, boolean isFilter,
                                                                 PriceGroupResponse orderPriceGroup,
                                                                 UserAddress address,
                                                                 ChannelMerchant channelMerchant) {
        // 2.查询可用优惠券
        Date theDate = new Date();
        List<StoreCouponUser> allList = storeCouponUserDao.selectList(new LambdaQueryWrapper<StoreCouponUser>()
                .eq(StoreCouponUser::getUid, request.getUserId())
                .eq(StoreCouponUser::getStatus, CouponUseStatusEnum.USABLE.getCode())
                .lt(StoreCouponUser::getStartTime, theDate)
                .gt(StoreCouponUser::getEndTime, theDate)
        );
        List<StoreCouponUserResponse> responseList = new ArrayList<>();
        if (CollectionUtils.isEmpty(storeCartResponse)) {
            return responseList;
        }
        List<Integer> productIdList = storeCartResponse.stream().map(StoreCartResponse::getProductId).distinct().collect(Collectors.toList());
        if(productIdList.size() < 1){
            return responseList;
        }

//        // 查询商品状态信息
//        List<StoreProduct> productList = storeProductService.getListInIds(productIdList);
//        // 过滤已下架商品
//        productIdList = productList.stream().filter(StoreProduct::getIsShow).map(StoreProduct::getId).collect(Collectors.toList());
//
//        //查询商户商品的上下架状态和推荐状态
//        List<StoreProductMer> merchantStoreProducts = storeProductMerService.getBaseMapper().selectList(Wrappers.<StoreProductMer>lambdaQuery()
//                .eq(StoreProductMer :: getMerId, channelMerchant.getId())
//                .in(StoreProductMer :: getProductId, productIdList)
//                .last("LIMIT 1"));
//        // 筛选未下架商品
//        productIdList = merchantStoreProducts.stream().filter(i -> "0".equals(i.getIsNotShow())).map(StoreProductMer::getId).collect(Collectors.toList());

        List<StoreCouponUser> resultList = new ArrayList<>();
        for (StoreCouponUser storeCouponUser : allList) {
            //可用优惠券商品id
            boolean flag = true;
            List<Integer> primaryKeyIdList = new ArrayList<>();
            switch (storeCouponUser.getUseType()){
                //全场通用
                case 1:
                    primaryKeyIdList = productIdList;
                    flag = false;
                    break;
                //商品券
                case 2:
                    List<StoreProductCoupon> list = storeProductCouponService.list(Wrappers.lambdaQuery(StoreProductCoupon.class).select(StoreProductCoupon::getProductId)
                            .eq(StoreProductCoupon::getIssueCouponId, storeCouponUser.getCouponId()).in(StoreProductCoupon::getProductId, productIdList));
                    primaryKeyIdList = list.stream().map(StoreProductCoupon::getProductId).distinct().collect(Collectors.toList());
                    if(CollectionUtils.isEmpty(primaryKeyIdList)){
                        continue;
                    }
                    break;
                //品类券
                case 3:
                    List<StoreProduct> storeProductList = storeProductService.list(Wrappers.lambdaQuery(StoreProduct.class).eq(StoreProduct::getIsShow, 1).in(StoreProduct::getId, productIdList));
                    CouponProductRangeDTO couponProductRangeDTO = JSONObject.parseObject(storeCouponUser.getPrimaryKey(), CouponProductRangeDTO.class);
                    for (StoreProduct storeProduct : storeProductList) {
                        if(CollectionUtils.isNotEmpty(couponProductRangeDTO.getTempIds()) && !couponProductRangeDTO.getTempIds().contains(storeProduct.getTempId())){
                            continue;
                        }
                        if(CollectionUtils.isNotEmpty(couponProductRangeDTO.getBrandids()) && !couponProductRangeDTO.getBrandids().contains(storeProduct.getBrandId())){
                            continue;
                        }
                        if(CollectionUtils.isNotEmpty(couponProductRangeDTO.getCateIds()) && !couponProductRangeDTO.getCateIds().contains(storeProduct.getCateId())){
                            continue;
                        }
                        if(CollectionUtils.isNotEmpty(couponProductRangeDTO.getSeasons()) && !couponProductRangeDTO.getSeasons().contains(storeProduct.getSeasonCode())){
                            continue;
                        }
                        primaryKeyIdList.add(storeProduct.getId());
                    }
                    if(CollectionUtils.isEmpty(primaryKeyIdList)){
                        continue;
                    }
                    break;
                default:
                    continue;
            }

            // 可用商品
            BigDecimal price;
            if(flag){
                List<Integer> finalPrimaryKeyIdList = primaryKeyIdList;
                List<StoreCartResponse> storeCartResponseList = storeCartResponse.stream()
                        .filter(e -> finalPrimaryKeyIdList.contains(e.getProductId())).collect(Collectors.toList());
                price = priceUtil.checkCouponPrice(storeCartResponseList, address, channelMerchant,storeCouponUser.getMinPrice());
            }else {
                price = orderPriceGroup.getTotalPrice();
                if(channelMerchant.getAppletType() == 1){
                    price = price.add(orderPriceGroup.getStorePostage());
                }
                price = price.subtract(storeCouponUser.getMinPrice());
            }
            if(price.compareTo(BigDecimal.ZERO)<0){
                continue;
            }
            resultList.add(storeCouponUser);
        }

        resultList = resultList.stream().distinct().sorted(Comparator.comparing(StoreCouponUser::getMoney).reversed()).collect(Collectors.toList());
        if (isFilter) {
            List<Integer> canCouponIds = resultList.stream().map(StoreCouponUser::getId).collect(Collectors.toList());
            boolean cnaFlag = CollectionUtils.isEmpty(canCouponIds);
            // 未使用优惠券
            List<StoreCouponUser> usableList = storeCouponUserDao.selectList(new LambdaQueryWrapper<StoreCouponUser>()
                    .eq(StoreCouponUser::getUid, request.getUserId())
                    .eq(StoreCouponUser::getStatus, CouponUseStatusEnum.USABLE.getCode())
//                    .gt(StoreCouponUser::getStartTime, theDate)
                    .gt(StoreCouponUser::getEndTime, theDate)
                    .orderByDesc(StoreCouponUser::getMoney)
            );
            usableList.forEach(c -> {
                StoreCouponUserResponse response = new StoreCouponUserResponse();
                BeanUtils.copyProperties(c, response);
                response.setUseStartTime(c.getStartTime());
                response.setUseEndTime(c.getEndTime());
                if (cnaFlag) {
                    response.setUseStatus(1);
                } else {
                    if (canCouponIds.contains(c.getId())) {
                        response.setUseStatus(0);
                    } else {
                        response.setUseStatus(2);
                    }
                }
                responseList.add(response);
            });
            // 使用状态升序，金额降序
            return responseList.stream().sorted(Comparator.comparing(StoreCouponUserResponse::getUseStatus)
                    .thenComparing(StoreCouponUserResponse::getMoney, Comparator.reverseOrder())).collect(Collectors.toList());
        }

        resultList.forEach(c -> {
            StoreCouponUserResponse response = new StoreCouponUserResponse();
            BeanUtils.copyProperties(c, response);
            response.setUseStartTime(c.getStartTime());
            response.setUseEndTime(c.getEndTime());
            responseList.add(response);
        });

        return responseList;
    }

    /**
     * 定时任务-更新用户优惠券状态
     */
    @Override
    public void syncCouponUserStatus() {
        // 1.查询已过期优惠券
        LambdaQueryWrapper<StoreCouponUser> wrapper = new LambdaQueryWrapper();
        wrapper.select(StoreCouponUser::getId);
        wrapper.eq(StoreCouponUser::getStatus, CouponUseStatusEnum.USABLE.getCode());
        wrapper.lt(StoreCouponUser::getEndTime, new Date());
        List<StoreCouponUser> list = storeCouponUserDao.selectList(wrapper);
        List<Integer> idList = list.stream().map(StoreCouponUser::getId).collect(Collectors.toList());
        // 2.更新状态
        if (CollectionUtils.isNotEmpty(list)) {
            List<List<Integer>> partition = Lists.partition(idList, 500);
            StoreCouponUser updateCouponUser = new StoreCouponUser();
            updateCouponUser.setStatus(CouponUseStatusEnum.DISABLES.getCode());
            partition.forEach(i -> {
                storeCouponUserDao.update(updateCouponUser,
                        new LambdaQueryWrapper<StoreCouponUser>()
                                .in(StoreCouponUser::getId, i));
            });
        }
    }
}
